package de.stefanocke.roo.wicket.entity;

import java.util.HashSet;
import java.util.Set;

import org.apache.felix.scr.annotations.Reference;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.jpa.entity.RooJpaEntity;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.scanner.MemberDetails;
import org.springframework.roo.model.JavaType;

import de.stefanocke.roo.wicket.base.ItdMetadataCreationParams;
import de.stefanocke.roo.wicket.base.ModelClassAwareItdMetadataProviderBase;
import de.stefanocke.roo.wicket.base.ModelClassAwareMetadataCreationParams;
import de.stefanocke.roo.wicket.model.JavaTypeMetadataDetails;
import de.stefanocke.roo.wicket.model.ModelClassService;
import de.stefanocke.roo.wicket.persistence.PersistenceMetadataDetails;
import de.stefanocke.roo.wicket.persistence.PersistenceMetadataService;

/**
 * Adds interfaces like Identifiable, Versioned, ... to Roo entities.
 * 
 * @author stoc
 * 
 */
// @Component
// @Service
public class EntityInterfacesMetadataProvider extends
		ModelClassAwareItdMetadataProviderBase<EntityInterfacesMetadata, Void> {
	
	@Reference
	protected PersistenceMetadataService persistenceMetadataService;
	
	@Reference
	protected ModelClassService modelClassService; 

	public EntityInterfacesMetadataProvider() {
		super(EntityInterfacesMetadata.class, null);
	}

	@Override
	protected Set<Class<?>> getTriggers() {
		Set<Class<?>> classes = new HashSet<Class<?>>();
		classes.add(RooJpaEntity.class);
		classes.add(RooJpaActiveRecord.class);
		return classes;
	}

	@Override
	protected ItdTypeDetailsProvidingMetadataItem getMetadataInternal(ModelClassAwareMetadataCreationParams<Void> cmcp) {
		
		PersistenceMetadataDetails persistenceDetails = getPersistenceDetails(cmcp.getModelClass(), cmcp.getMid());
		return new EntityInterfacesMetadata(cmcp, persistenceDetails.getIdentifierAccessorMethod(), persistenceDetails.getVersionAccessorMethod());
	}

	@Override
	protected String[] optionalStereotypes() {
		return EntityInterfacesMetadata.INTERFACES;
	}

	@Override
	protected JavaType getModelClass(ItdMetadataCreationParams<Void> cmcp) {
		// Here, the governor itself is the model class.
		return PhysicalTypeIdentifier.getJavaType(cmcp.getGovernorPhysicalTypeMetadata().getId());
	}

	private PersistenceMetadataDetails getPersistenceDetails(JavaType modelClass, String mid) {

		MemberDetails memberDetails = modelClassService.getMemberDetails(modelClass, mid);
		PersistenceMetadataDetails details = persistenceMetadataService.getJavaTypePersistenceMetadataDetails(
				modelClass, memberDetails , mid);
		if (details == null) {

			// sometimes, the persistence type details are temporarily not
			// available due to recursive
			// Metadata retrievals happening concurrently to cache evictions
			// triggered by file monitor.
			// This is especially true, if the model class is the entity itself
			// and its
			// entity metadata is not available yet.
			// In these cases, the ValidationException will be silent. That is,
			// no metadata is produced (for now), but no error is displayed to
			// the user.
	
			validationError(mid, modelClass + " is not a persistent type.", true);
		}
		return details;
	}
}
